#include <string.h>
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::endl;
using std::ostream;
using std::istream;
using std::vector;
#define SIZEOF_REF_COUNT 4
class CowString {
private://私有类
    class CharProxy {
    public://公有成员函数
        // static void t() {};
        char& operator=(const char& rhs) {
            if (m_cow.get_ref_conut() > 1) {
                m_cow.decrement_ref_conut();
                char* temp = new char[strlen(m_cow.m_pstr) + 1 + SIZEOF_REF_COUNT] {} + SIZEOF_REF_COUNT;
                strcpy(temp, m_cow.m_pstr);
                m_cow.m_pstr = temp;
                m_cow.increment_ref_conut();
            }
            return m_cow.m_pstr[m_index] = rhs;
        }
        friend class  CowString;
        friend ostream& operator<<(ostream& os, const CharProxy& rhs);
    private://私有成员函数
        CharProxy(CowString& cow, size_t index)
            :m_cow(cow)
            , m_index(index)
        {
            cout << "CharProxy(CowString & cow, size_t index)" << endl;
        }
    private://私有数据成员
        CowString& m_cow;
        size_t m_index;
    };//end of class CharProxy
public://公有函数
    // no arg constructor
    CowString()
        :m_pstr(new char[SIZEOF_REF_COUNT + 1] {} + SIZEOF_REF_COUNT)
    {
        increment_ref_conut();
        cout << "CowString()" << endl;
    }
    // arg constructor
    CowString(const char* pStr)
        :m_pstr(new char[strlen(pStr) + SIZEOF_REF_COUNT + 1] {} + SIZEOF_REF_COUNT)
    {
        strcpy(m_pstr, pStr);
        increment_ref_conut();
        cout << "CowString(const char* pStr)" << endl;
    }
    // destructor
    ~CowString() {
        decrement_ref_conut();
        destroy();
    }
    // copy constructor
    CowString(const CowString& cowString)
        :m_pstr(cowString.m_pstr)
    {
        increment_ref_conut();
    }
    // operator =
    CowString& operator=(const CowString& cowString) {
        //排除自赋值
        if (this != &cowString) {
            //自减引用计数
            decrement_ref_conut();
            //可能destroy
            destroy();
            //修改指向
            m_pstr = cowString.m_pstr;
            //自增引用计数
            increment_ref_conut();
        }
        return *this;
    }
    // operator []
    CharProxy operator[](size_t index) {
        return CharProxy(*this, index);
    }
    // operator << 
    friend
        ostream& operator<<(ostream& os, const CowString& cowString);
    friend ostream& operator<<(ostream& os, const CharProxy& rhs);
    // 用于获取字符串长度的方法
    size_t size()
    {
        return strlen(m_pstr);
    }
    // 返回C风格字符串
    char* c_str()
    {
        return m_pstr;
    }
private://私有函数
    //得到引用计数值
    int get_ref_conut() {
        return *(int*)(m_pstr - SIZEOF_REF_COUNT);
    }
    //引用计数++
    int increment_ref_conut() {
        return (*(int*)(m_pstr - SIZEOF_REF_COUNT))++;
    }
    //引用计数--
    int decrement_ref_conut() {
        return (*(int*)(m_pstr - SIZEOF_REF_COUNT))--;
    }
    //销毁
    void destroy() {
        if (get_ref_conut() == 0) {
            delete (m_pstr - SIZEOF_REF_COUNT);
            m_pstr = nullptr;
        }
    }
    friend void test();
private://私有数据成员
    char* m_pstr;

};//end of class CowString

// operator << 
ostream& operator<<(ostream& os, const CowString& rhs) {
    cout << rhs.m_pstr;
    return os;
}
ostream& operator<<(ostream& os, const CowString::CharProxy& rhs) {
    os << rhs.m_cow.m_pstr[rhs.m_index];
    return os;
}

void test() {
    CowString str1;
    CowString str2("hello");
    // cout << str1.get_ref_conut() << endl;
    CowString str3(str2);
    // cout << str2.get_ref_conut() << endl;
    str1 = str2;
    // cout << str2.get_ref_conut() << endl;
    // cout << str1 << endl;
    // cout << str2 << endl;
    // cout << str3 << endl;
    // cout << "--------------ref_count ----------------" << endl;
    // cout << str1.get_ref_conut() << endl;
    // cout << str2.get_ref_conut() << endl;
    // cout << str3.get_ref_conut() << endl;
    // cout << "------------------------------" << endl;
    // str1[0] = 'A';
    cout << str1[0] << endl;
    cout << str1 << endl;
    cout << str2 << endl;
    cout << str3 << endl;
    cout << "--------------ref_count ----------------" << endl;
    cout << str1.get_ref_conut() << endl;
    cout << str2.get_ref_conut() << endl;
    cout << str3.get_ref_conut() << endl;


}
int main() {
    // test();
    CowString str1("hello");
    str1[0] = 'A';
    cout << str1[0] << endl;
    cout << str1 << endl;

    return 0;
}